using System.Collections.Generic;

namespace System.DataStructures
{
	/// <summary>
	/// Provides an extended interface for the abstraction of sets.
	/// </summary>
	/// <typeparam name="T">The type of elements in the set.</typeparam>
	/// <remarks></remarks>
	internal interface ISetEx<T> : ISet<T>
	{
		/// <summary>
		/// Gets a value indicating whether this instance is empty.
		/// </summary>
		/// <remarks></remarks>
		bool IsEmpty { get; }

		/// <summary>
		/// Create a new instance of the same type and populate it with the specified contents.
		/// </summary>
		/// <returns>A cloned instance.</returns>
		/// <remarks></remarks>
		ISetEx<T> CloneType(IEnumerable<T> initialContents = null);

		/// <summary>
		/// Returns <see langword="true"/> if the set contains all the elements in the specified collection.
		/// </summary>
		/// <param name="items">A collection of objects.</param>
		/// <returns><see langword="true"/> if the set contains all the elements in the specified collection, <see langword="false"/> otherwise.</returns>
		/// <remarks></remarks>
		bool ContainsAll(IEnumerable<T> items);

		/// <summary>
		/// Performs a subtraction of the distinct elements of the enumeration from this set.
		/// The result is a <c>Clone()</c> of this set containing all elements that were not in the enumeration.
		/// The <c>Difference()</c> operation does not modify the inputs.
		/// </summary>
		/// <param name="items">The items.</param>
		/// <returns>A set containing the result of <c>a - b</c>.</returns>
		/// <remarks></remarks>
		ISetEx<T> Difference(IEnumerable<T> items);

		/// <summary>
		/// Performs a subtraction of the distinct elements of the enumeration from this set.
		/// <seealso cref="ISet{T}.ExceptWith(IEnumerable{T})"/>
		/// </summary>
		/// <param name="items">The items.</param>
		/// <remarks></remarks>
		void DifferenceWith(IEnumerable<T> items); //proxy for ExceptWith

		/// <summary>
		/// Performs an intersection of the two sets.
		/// The result is a <c>Clone()</c> of this set containing all elements that are in both sets.
		/// The <c>Intersect()</c> operation does not modify the inputs.
		/// </summary>
		/// <param name="items">The items.</param>
		/// <returns>A set containing the result of <c>a & b</c>.</returns>
		/// <remarks></remarks>
		ISetEx<T> Intersect(IEnumerable<T> items);

		/// <summary>
		/// Performs an exclusive-or of the two sets.
		/// The result is a <c>Clone()</c> of this set containing all elements that are only in one of the sets, but not in both.
		/// The <c>SymmetricDifference()</c> operation does not modify the inputs.
		/// </summary>
		/// <param name="items">The items.</param>
		/// <returns>A set containing the result of <c>a ^ b</c>.</returns>
		/// <remarks></remarks>
		ISetEx<T> SymmetricDifference(IEnumerable<T> items);

		/// <summary>
		/// Performs an exclusive-or of the two sets.
		/// <seealso cref="ISet{T}.SymmetricExceptWith(IEnumerable{T})"/>
		/// </summary>
		/// <param name="items">The items.</param>
		/// <remarks></remarks>
		void SymmetricDifferenceWith(IEnumerable<T> items);

		/// <summary>
		/// Performs a union of the two sets.
		/// The result is a <c>Clone()</c> of this set containing all distinct elements from both sets.
		/// The <c>Union()</c> operation does not modify the inputs.
		/// </summary>
		/// <param name="items">The items.</param>
		/// <returns>A set containing the result of <c>a | b</c>.</returns>
		/// <remarks></remarks>
		ISetEx<T> Union(IEnumerable<T> items);
	}
}

//Change this to true if the ISet<T> interface is not defined
#if false
namespace System.Collections.Generic
{
	/// <summary>
	/// Provides the base interface for the abstraction of sets.
	/// </summary>
	/// <typeparam name="T">The type of elements in the set.</typeparam>
	internal interface ISet<T> : ICollection<T>
	{
		/// <summary>
		/// Adds an element to the current set and returns a value to indicate if the element was successfully added.
		/// </summary>
		/// <param name="item">The element to add to the set.</param>
		/// <returns>true if the element is added to the set; false if the element is already in the set.</returns>
		/// <remarks></remarks>
		new bool Add(T item);

		/// <summary>
		/// Removes all elements in the specified collection from the current set.
		/// </summary>
		/// <param name="other">The collection of items to remove from the set.</param><exception cref="T:System.ArgumentNullException"><paramref name="other"/> is null.</exception>
		void ExceptWith(IEnumerable<T> other);

		/// <summary>
		/// Modifies the current set so that it contains only elements that are also in a specified collection.
		/// </summary>
		/// <param name="other">The collection to compare to the current set.</param><exception cref="T:System.ArgumentNullException"><paramref name="other"/> is null.</exception>
		void IntersectWith(IEnumerable<T> other);

		/// <summary>
		/// Determines whether the current set is a property (strict) subset of a specified collection.
		/// </summary>
		/// 
		/// <returns>
		/// true if the current set is a correct subset of <paramref name="other"/>; otherwise, false.
		/// </returns>
		/// <param name="other">The collection to compare to the current set.</param><exception cref="T:System.ArgumentNullException"><paramref name="other"/> is null.</exception>
		bool IsProperSubsetOf(IEnumerable<T> other);

		/// <summary>
		/// Determines whether the current set is a correct superset of a specified collection.
		/// </summary>
		/// 
		/// <returns>
		/// true if the <see cref="T:System.Collections.Generic.ISet`1"/> object is a correct superset of <paramref name="other"/>; otherwise, false.
		/// </returns>
		/// <param name="other">The collection to compare to the current set. </param><exception cref="T:System.ArgumentNullException"><paramref name="other"/> is null.</exception>
		bool IsProperSupersetOf(IEnumerable<T> other);

		/// <summary>
		/// Determines whether a set is a subset of a specified collection.
		/// </summary>
		/// 
		/// <returns>
		/// true if the current set is a subset of <paramref name="other"/>; otherwise, false.
		/// </returns>
		/// <param name="other">The collection to compare to the current set.</param><exception cref="T:System.ArgumentNullException"><paramref name="other"/> is null.</exception>
		bool IsSubsetOf(IEnumerable<T> other);

		/// <summary>
		/// Determines whether the current set is a superset of a specified collection.
		/// </summary>
		/// 
		/// <returns>
		/// true if the current set is a superset of <paramref name="other"/>; otherwise, false.
		/// </returns>
		/// <param name="other">The collection to compare to the current set.</param><exception cref="T:System.ArgumentNullException"><paramref name="other"/> is null.</exception>
		bool IsSupersetOf(IEnumerable<T> other);

		/// <summary>
		/// Determines whether the current set overlaps with the specified collection.
		/// </summary>
		/// 
		/// <returns>
		/// true if the current set and <paramref name="other"/> share at least one common element; otherwise, false.
		/// </returns>
		/// <param name="other">The collection to compare to the current set.</param><exception cref="T:System.ArgumentNullException"><paramref name="other"/> is null.</exception>
		bool Overlaps(IEnumerable<T> other);

		/// <summary>
		/// Determines whether the current set and the specified collection contain the same elements.
		/// </summary>
		/// 
		/// <returns>
		/// true if the current set is equal to <paramref name="other"/>; otherwise, false.
		/// </returns>
		/// <param name="other">The collection to compare to the current set.</param><exception cref="T:System.ArgumentNullException"><paramref name="other"/> is null.</exception>
		bool SetEquals(IEnumerable<T> other);

		/// <summary>
		/// Modifies the current set so that it contains only elements that are present either in the current set or in the specified collection, but not both.
		/// </summary>
		/// <param name="other">The collection to compare to the current set.</param><exception cref="T:System.ArgumentNullException"><paramref name="other"/> is null.</exception>
		void SymmetricExceptWith(IEnumerable<T> other);

		/// <summary>
		/// Modifies the current set so that it contains all elements that are present in both the current set and in the specified collection.
		/// </summary>
		/// <param name="other">The collection to compare to the current set.</param><exception cref="T:System.ArgumentNullException"><paramref name="other"/> is null.</exception>
		void UnionWith(IEnumerable<T> other);
	}
}
#endif